// @Author EthanScriptOn
// @Desc
package config_source_loader

import (
	"errors"
	"gitee.com/fatzeng/srf_switch_basic_components/custom_exp"
	"gitee.com/fatzeng/srf_switch_basic_components/resource"
	"gitee.com/fatzeng/srf_switch_config/config_define"
)

type SourceLoaders interface {
	AddSourceLoader(loader SourceLoader) error
	RemoveSourceLoader(configType config_define.ConfigSourceType) error
	GetSourceLoader(configType config_define.ConfigSourceType) (SourceLoader, error)
	GetAllSourceLoader() ([]SourceLoader, error)
}

type MultiSourceLoaders struct {
	loaders *resource.ResourceManager
}

func GenerateMultiSourceLoaders() *MultiSourceLoaders {
	return &MultiSourceLoaders{
		loaders: resource.GenerateResourceManager(true),
	}
}

func (m *MultiSourceLoaders) AddSourceLoader(loader SourceLoader) error {
	return m.loaders.OperateResource(&resource.ResourceOptions{
		DoExecute: func(container map[interface{}]interface{}) error {
			if _, exists := container[loader.GetConfigSourceType()]; exists {
				return errors.New("a loader for the same config source type already exists")
			}
			container[loader.GetConfigSourceType()] = loader
			return nil
		},
	})
}

func (m *MultiSourceLoaders) RemoveSourceLoader(configType config_define.ConfigSourceType) error {
	return m.loaders.OperateResource(&resource.ResourceOptions{
		DoExecute: func(container map[interface{}]interface{}) error {
			delete(container, configType)
			return nil
		},
	})
}

func (m *MultiSourceLoaders) GetSourceLoader(configType config_define.ConfigSourceType) (SourceLoader, error) {
	resource, err, exists := m.loaders.GetResource(configType)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, custom_exp.GenerateNoResourceError(configType, errors.New("no loader found for the specified config source type"))
	}
	sl, ok := resource.(SourceLoader)
	if !ok {
		return nil, errors.New("loader for the specified config source type is not a SourceLoader")
	}
	return sl, nil
}

func (m *MultiSourceLoaders) GetAllSourceLoader() ([]SourceLoader, error) {
	allSourceLoaders := make([]SourceLoader, 0)
	return allSourceLoaders, m.loaders.OperateResource(&resource.ResourceOptions{
		DoExecute: func(container map[interface{}]interface{}) error {
			for _, sourceLoader := range container {
				sourceLoaderInstance, ok := sourceLoader.(SourceLoader)
				if !ok {
					return errors.New("loader for the specified config source type is not a SourceLoader")
				}
				allSourceLoaders = append(allSourceLoaders, sourceLoaderInstance)
			}
			return nil
		},
	})
}
